package com.yfp.group.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyV3Response;
import com.github.binarywang.wxpay.bean.notify.WxPayPartnerNotifyV3Result;
import com.github.binarywang.wxpay.bean.notify.WxPayPartnerRefundNotifyV3Result;
import com.github.binarywang.wxpay.bean.request.WxPayPartnerOrderCloseV3Request;
import com.github.binarywang.wxpay.bean.request.WxPayPartnerOrderQueryV3Request;
import com.github.binarywang.wxpay.bean.request.WxPayPartnerUnifiedOrderV3Request;
import com.github.binarywang.wxpay.bean.result.WxPayPartnerOrderQueryV3Result;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result;
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.yfp.common.core.domain.R;
import com.yfp.common.core.exception.ServiceException;
import com.yfp.group.config.WxPayConfiguration;
import com.yfp.group.config.WxPayProperties;
import com.yfp.group.domain.dto.CreateWxPayOrderDTO;
import com.yfp.group.enums.PayTypeEnums;
import com.yfp.group.enums.WxPayAttach;
import com.yfp.group.service.EnterpriseCapitalService;
import com.yfp.group.service.EnterpriseOrderService;
import com.yfp.group.service.EnterpriseService;
import com.yfp.group.service.PayService;
import com.yfp.tissue.api.RemotePositionService;
import com.yfp.tissue.domain.Position;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Objects;

@Slf4j
@Service
public class PayServiceImpl implements PayService {

    @Resource
    private WxPayProperties properties;
    @Resource
    private EnterpriseService enterpriseService;
    @Resource
    private EnterpriseOrderService enterpriseOrderService;
    @Resource
    private EnterpriseCapitalService enterpriseCapitalService;
    @Resource
    private RemotePositionService remotePositionService;

    @Override
    public WxPayUnifiedOrderV3Result.JsapiResult createWxJsapiPayOrder(CreateWxPayOrderDTO createWxPayOrderDTO) {
        WxPayProperties.Config payConfig = properties.getConfigs().get(2);

        WxPayPartnerUnifiedOrderV3Request wxPayPartnerUnifiedOrderV3Request = new WxPayPartnerUnifiedOrderV3Request();
        wxPayPartnerUnifiedOrderV3Request.setSpAppid(payConfig.getAppId());
        wxPayPartnerUnifiedOrderV3Request.setSpMchId(payConfig.getMchId());
        wxPayPartnerUnifiedOrderV3Request.setSubMchId(createWxPayOrderDTO.getSubMchId());
        wxPayPartnerUnifiedOrderV3Request.setDescription(createWxPayOrderDTO.getDescription());
        wxPayPartnerUnifiedOrderV3Request.setOutTradeNo(createWxPayOrderDTO.getOutTradeNo());
        wxPayPartnerUnifiedOrderV3Request.setTimeExpire(DateUtil.format(createWxPayOrderDTO.getTimeExpire(), DatePattern.UTC_WITH_XXX_OFFSET_PATTERN));
        wxPayPartnerUnifiedOrderV3Request.setNotifyUrl(properties.getNotifyUrl().getCreate());
        wxPayPartnerUnifiedOrderV3Request.setAttach(createWxPayOrderDTO.getAttach());

        // 微信要求订单总金额，单位为分，所以要乘以100用来转换
        WxPayPartnerUnifiedOrderV3Request.Amount amount = new WxPayPartnerUnifiedOrderV3Request.Amount();
        amount.setTotal(NumberUtil.mul(createWxPayOrderDTO.getTotalPrice(), new BigDecimal("100")).intValue());
        wxPayPartnerUnifiedOrderV3Request.setAmount(amount);

        // 支付者信息。sp_openid 和 sub_openid 两个字段必须要填一个
        WxPayPartnerUnifiedOrderV3Request.Payer payer = new WxPayPartnerUnifiedOrderV3Request.Payer();
        payer.setSpOpenid(createWxPayOrderDTO.getOpenid());
        wxPayPartnerUnifiedOrderV3Request.setPayer(payer);

        WxPayUnifiedOrderV3Result.JsapiResult partnerOrderV3 = null;
        try {
            WxPayService mxPayService = WxPayConfiguration.getMxPayService(payConfig);
            partnerOrderV3 = mxPayService.createPartnerOrderV3(TradeTypeEnum.JSAPI, wxPayPartnerUnifiedOrderV3Request);
            log.info("创建微信预支付订单成功。创建微信预支付订单orderId:{},JsapiResult:{}", createWxPayOrderDTO.getOutTradeNo(), partnerOrderV3);
        } catch (WxPayException e) {
            log.error("创建微信预支付订单失败。orderId:{}", createWxPayOrderDTO.getOutTradeNo(), e);
            throw new ServiceException(e.getMessage());
        }
        return partnerOrderV3;
    }

    @Override
    public String createWxNativePayOrder(CreateWxPayOrderDTO createWxPayOrderDTO) {
        WxPayProperties.Config payConfig = properties.getConfigs().get(2);

        WxPayPartnerUnifiedOrderV3Request wxPayPartnerUnifiedOrderV3Request = new WxPayPartnerUnifiedOrderV3Request();
        wxPayPartnerUnifiedOrderV3Request.setSpAppid(payConfig.getAppId());
        wxPayPartnerUnifiedOrderV3Request.setSpMchId(payConfig.getMchId());
        wxPayPartnerUnifiedOrderV3Request.setSubMchId(createWxPayOrderDTO.getSubMchId());
        wxPayPartnerUnifiedOrderV3Request.setDescription(createWxPayOrderDTO.getDescription());
        wxPayPartnerUnifiedOrderV3Request.setOutTradeNo(createWxPayOrderDTO.getOutTradeNo());
        wxPayPartnerUnifiedOrderV3Request.setTimeExpire(DateUtil.format(createWxPayOrderDTO.getTimeExpire(), DatePattern.UTC_WITH_XXX_OFFSET_PATTERN));
        wxPayPartnerUnifiedOrderV3Request.setNotifyUrl(properties.getNotifyUrl().getCreate());
        wxPayPartnerUnifiedOrderV3Request.setAttach(createWxPayOrderDTO.getAttach());

        // 微信要求订单总金额，单位为分，所以要乘以100用来转换
        WxPayPartnerUnifiedOrderV3Request.Amount amount = new WxPayPartnerUnifiedOrderV3Request.Amount();
        amount.setTotal(NumberUtil.mul(createWxPayOrderDTO.getTotalPrice(), new BigDecimal("100")).intValue());
        wxPayPartnerUnifiedOrderV3Request.setAmount(amount);

        try {
            WxPayService mxPayService = WxPayConfiguration.getMxPayService(payConfig);
            String codeUrl = mxPayService.createPartnerOrderV3(TradeTypeEnum.NATIVE, wxPayPartnerUnifiedOrderV3Request);
            log.info("创建微信预支付订单成功。创建微信预支付订单orderId:{},codeUrl:{}", createWxPayOrderDTO.getOutTradeNo(), codeUrl);
            return codeUrl;
        } catch (WxPayException e) {
            log.error("创建微信预支付订单失败。orderId:{}", createWxPayOrderDTO.getOutTradeNo(), e);
            throw new ServiceException(e.getMessage());
        }
    }

    @Override
    public void createBalancePayOrder(CreateWxPayOrderDTO createWxPayOrderDTO) {
        // 模拟微信支付
        WxPayPartnerNotifyV3Result.DecryptNotifyResult decryptNotifyResult = new WxPayPartnerNotifyV3Result.DecryptNotifyResult();
        decryptNotifyResult.setOutTradeNo(createWxPayOrderDTO.getOutTradeNo());
        decryptNotifyResult.setSuccessTime(DateUtil.format(DateUtil.date(), DatePattern.UTC_WITH_XXX_OFFSET_PATTERN));
        enterpriseOrderService.parseOrderNotifyResult(decryptNotifyResult);
        // 扣减账户余额
        enterpriseCapitalService.subBalance(createWxPayOrderDTO);
    }

    @Override
    public String parseOrderNotifyResult(String xmlData) {
        log.info("微信支付回调xmlData:{}", xmlData);
        WxPayService mxPayService = WxPayConfiguration.getMxPayService(properties.getConfigs().get(2));
        WxPayPartnerNotifyV3Result wxPayPartnerNotifyV3Result = null;
        try {
            wxPayPartnerNotifyV3Result = mxPayService.parsePartnerOrderNotifyV3Result(xmlData, null);
            log.info("微信支付回调Result:{}", wxPayPartnerNotifyV3Result);
        } catch (WxPayException e) {
            log.error("支付回调失败", e);
            return WxPayNotifyV3Response.fail("失败");
        }
        WxPayPartnerNotifyV3Result.DecryptNotifyResult result = wxPayPartnerNotifyV3Result.getResult();
        switch (result.getTradeState()) {
            case WxPayConstants.WxpayTradeStatus.SUCCESS -> {
                try {
                    // 注册保证金
                    if (WxPayAttach.REGISTER_PAY.getCode().equals(result.getAttach())) {
                        enterpriseService.parseOrderNotifyResult(result);
                    }
                    // 订单购买套餐
                    else if (WxPayAttach.ORDER_BUY_COMBO.getCode().equals(result.getAttach())) {
                        enterpriseOrderService.parseOrderNotifyResult(result);
                    }
                    // 账户充值
                    else if (WxPayAttach.ACCOUNT_RECHARGE.getCode().equals(result.getAttach())) {
                        enterpriseCapitalService.parseOrderNotifyResult(result);
                    }
                } catch (Exception e) {
                    log.error("支付回调失败", e);
                    return WxPayNotifyV3Response.fail("失败");
                }
            }
        }
        return WxPayNotifyV3Response.success("成功");
    }

    @Override
    public String parseOrderNativeNotifyResult(String xmlData) {
        log.info("微信二维码支付回调xmlData:{}", xmlData);
        return "";
    }

    @Override
    public String parseRefundNotifyResult(String xmlData) {
        log.info("退款回调xmlData:{}", xmlData);
        WxPayPartnerRefundNotifyV3Result wxPayPartnerRefundNotifyV3Result = null;
        try {
            WxPayService mxPayService = WxPayConfiguration.getMxPayService(properties.getConfigs().get(2));
            wxPayPartnerRefundNotifyV3Result = mxPayService.parsePartnerRefundNotifyV3Result(xmlData, null);
        } catch (WxPayException e) {
            log.error("退款回调失败", e);
            return WxPayNotifyV3Response.fail("失败");
        }
        WxPayPartnerRefundNotifyV3Result.DecryptNotifyResult result = wxPayPartnerRefundNotifyV3Result.getResult();
        switch (result.getRefundStatus()) {
            case WxPayConstants.RefundStatus.SUCCESS -> {
                enterpriseService.parseRefundNotifyResult(result);
            }
        }
        return WxPayNotifyV3Response.success("成功");
    }

    @Override
    public WxPayPartnerOrderQueryV3Result getOrderStatus(String outTradeNo, String subMchId) {
        WxPayProperties.Config payConfig = properties.getConfigs().get(2);
        WxPayPartnerOrderQueryV3Request wxPayPartnerOrderQueryV3Request = new WxPayPartnerOrderQueryV3Request();
        wxPayPartnerOrderQueryV3Request.setSpMchId(payConfig.getMchId());
        wxPayPartnerOrderQueryV3Request.setSubMchId(subMchId);
        wxPayPartnerOrderQueryV3Request.setOutTradeNo(outTradeNo);

        try {
            WxPayService mxPayService = WxPayConfiguration.getMxPayService(payConfig);
            WxPayPartnerOrderQueryV3Result wxPayPartnerOrderQueryV3Result = mxPayService.queryPartnerOrderV3(wxPayPartnerOrderQueryV3Request);
            log.info("查询微信订单成功。查询微信订单orderId:{},wxPayPartnerOrderQueryV3Result:{}", outTradeNo, wxPayPartnerOrderQueryV3Result);
            return wxPayPartnerOrderQueryV3Result;
        } catch (WxPayException e) {
            log.error("查询微信订单失败。orderId:{}", outTradeNo, e);
            throw new ServiceException(e.getMessage());
        }
    }

    @Override
    public String getSubMchIdByMachineId(String machineId) {
        R<Position> infoByMachineId = remotePositionService.getInfoByMachineId(machineId);
        if (R.isError(infoByMachineId)) {
            throw new ServiceException(infoByMachineId.getMsg());
        }
        Position position = infoByMachineId.getData();
        if (Objects.isNull(position) || Objects.isNull(position.getProceedsAccount())) {
            throw new ServiceException("创客收款商户号不存在");
        }
        return position.getProceedsAccount();
    }

    @Override
    public void closeOrder(String outTradeNo, String subMchId) {
        WxPayProperties.Config payConfig = properties.getConfigs().get(2);

        WxPayService mxPayService = WxPayConfiguration.getMxPayService(payConfig);
        WxPayPartnerOrderCloseV3Request wxPayPartnerOrderCloseV3Request = new WxPayPartnerOrderCloseV3Request();
        wxPayPartnerOrderCloseV3Request.setOutTradeNo(outTradeNo);
        wxPayPartnerOrderCloseV3Request.setSpMchId(payConfig.getMchId());
        wxPayPartnerOrderCloseV3Request.setSubMchId(subMchId);
        try {
            mxPayService.closePartnerOrderV3(wxPayPartnerOrderCloseV3Request);
        } catch (WxPayException e) {
            log.error("关闭订单失败,outTradeNo:{}", outTradeNo, e);
        }
    }

    @Override
    public String orderSnToOutTradeNo(String orderSn, PayTypeEnums payTypeEnums) {
        String outTradeNo = orderSn + "_type_" + payTypeEnums.getCode();
        return outTradeNo;
    }

    @Override
    public String outTradeNoToOrderSn(String outTradeNo) {
        String orderSn = StrUtil.subBefore(outTradeNo, "_type_", false);
        return orderSn;
    }

}
